import matplotlib.pyplot as plt

# ========== PID 控制器类 ==========
class SimplePID:
    def __init__(self, kp=1.0, ki=0.1, kd=0.05, dt=1.0):
        # PID 系数
        self.kp = kp  # 比例增益
        self.ki = ki  # 积分增益
        self.kd = kd  # 微分增益
        self.dt = dt  # 控制周期（时间步长）

        # 内部状态变量
        self.integral = 0.0      # 积分项累加
        self.prev_error = 0.0    # 上一次误差，用于计算微分

    def compute(self, setpoint, measurement):
        """
        计算 PID 控制输出
        :param setpoint: 设定值
        :param measurement: 实际测量值
        :return: PID 控制器输出值（连续量）
        """
        # 误差计算
        error = setpoint - measurement

        # 积分项更新
        self.integral += error * self.dt

        # 微分项计算
        derivative = (error - self.prev_error) / self.dt

        # PID 控制器输出
        output = self.kp * error + self.ki * self.integral + self.kd * derivative

        # 保存误差，供下次计算使用
        self.prev_error = error

        return output


# ========== HVAC 控制器类 ==========
class HVACController:
    def __init__(self, season="winter"):
        """
        :param season: 控制模式，"winter"=加热，"summer"=制冷
        """
        self.season = season
        # 绑定一个 PID 控制器
        self.pid = SimplePID(kp=2.0, ki=0.1, kd=0.1, dt=1.0)

    def control(self, setTemp, roomTemp):
        """
        控制逻辑：根据 PID 输出决定执行器开关
        :param setTemp: 设定温度
        :param roomTemp: 实际温度
        :return: HVAC 动作（字符串）
        """
        pid_output = self.pid.compute(setTemp, roomTemp)

        if self.season == "winter":  # 冬季：加热模式
            return "HEATER ON" if pid_output > 0 else "HEATER OFF"
        elif self.season == "summer":  # 夏季：制冷模式
            return "COOLER ON" if pid_output > 0 else "COOLER OFF"
        else:
            return "SYSTEM OFF"


# ========== 仿真部分 ==========
controller = HVACController(season="winter")  # 模拟冬天，控制加热器

# 初始条件
roomTemp = 18.0  # 初始室温
setTemp = 22.0   # 设定温度

temps = []   # 用于存储温度曲线
actions = [] # 用于存储开关状态
steps = 50   # 仿真步数

for t in range(steps):
    # 控制器输出动作
    action = controller.control(setTemp, roomTemp)

    # 保存当前温度和动作
    temps.append(roomTemp)
    actions.append(1 if "ON" in action else 0)  # 转换为 0/1

    # 环境模型：根据执行器状态更新温度
    if action == "HEATER ON":
        roomTemp += 0.5   # 加热器开 → 温度上升
    else:
        roomTemp -= 0.1   # 加热器关 → 温度自然下降

# ========== 绘图 ==========
fig, ax1 = plt.subplots()

# 绘制温度曲线
ax1.plot(range(steps), temps, label="Room Temperature (°C)", color="tab:blue")
ax1.axhline(setTemp, color="tab:red", linestyle="--", label="Set Temperature")  # 设定温度线
ax1.set_xlabel("Time step")
ax1.set_ylabel("Temperature (°C)")
ax1.legend(loc="upper left")

# 绘制执行器状态（右轴）
ax2 = ax1.twinx()
ax2.step(range(steps), actions, label="Heater State (1=ON,0=OFF)", 
         color="tab:green", where="post")
ax2.set_ylabel("Heater State")
ax2.legend(loc="upper right")

plt.title("PID Control HVAC (winter mode, on/off actions)")
plt.show()
